/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.worlds.object;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.worlds.AssetLoader;
import net.worlds.AssetManager;
import net.worlds.WorldsException;
import net.worlds.Main;
import net.worlds.PropChangeHandler;
import org.jbox2d.common.Vec2D;


public class ParticleSystem extends GameObject implements Prop, Steppable {
    private Part part;
    private final List<Particle> particles = Collections.synchronizedList(new ArrayList<Particle>(128));
    private BufferedImage image;
    private double rate;
    private Vec2D gravity;
    private Vec2D force;
    private Vec2D randomness;
    private int lifetime;
    public ParticleSystem() throws WorldsException
    {
        super("ParticleSystem");
        constructor();
    }
    protected ParticleSystem(String type) throws WorldsException
    {
        super(type);
        constructor();
    }
    private void constructor()
    {
addPropChangeHandler("Parent", new PropChangeHandler()
        {
            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                onParentChanged((GameObject) oldValue, (GameObject) value);
                if(value instanceof Part)
                {
                    part = (Part) value;
                }
                else if(value == null && oldValue instanceof Part)
                    destructor((Part) oldValue);
            }
        });
        addPropChangeHandler("Image", new PropChangeHandler()
        {
            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                final String path = value.toString();
                Runnable r = new Runnable()
                {
                    public void run() {
                        try
                        {
                            image = AssetManager.loadImage(path, path);
                        } catch (Exception ex) {
                            System.err.println("Invalid image URL");
                        }
                    }
                };
                AssetLoader.getInstance().addItem(r);
            }
        });
        addPropChangeHandler("Rate", new PropChangeHandler()
        {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                float r = (Float) value;
                if(r < 0 || r > 1)
                    throw new RuntimeException("Rate should be > 0 and < 1");
                rate = r;
            }
        });
        addPropChangeHandler("Gravity", new PropChangeHandler()
        {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                Vec2D g = (Vec2D) value;
                gravity = g;
            }
        });
        addPropChangeHandler("Force", new PropChangeHandler()
        {
            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                Vec2D f = (Vec2D) value;
                force = f;
            }
        });
        addPropChangeHandler("Randomness", new PropChangeHandler()
        {
            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                Vec2D r = (Vec2D) value;
                randomness = r;
            }
        });
        addPropChangeHandler("Lifetime", new PropChangeHandler()
        {

            @Override
            public void handle(Object oldValue, Object value) throws WorldsException {
                lifetime = (int) ((Float)value * 1000);
            }

        });
    }
    @Override
    public void draw(Graphics g)
    {
        double scale = Main.getView().scaleFactor/8;
        synchronized(particles)
        {
            for(Particle p : particles)
            {
                Vec2D screenPos = p.pos.worldToScreen(Main.getView());
                int x = (int) screenPos.x;
                int y = (int) screenPos.y;
                g.setColor(Color.black);
                if(image == null)
                    continue;
                drawParticle((Graphics2D) g, p, scale, x, y);
            }
        }
    }
    private void stepParticle(final Particle p)
    {
            p.pos = p.pos.add(p.velocity);
            p.velocity = p.velocity.add(gravity);
            if(System.currentTimeMillis() - p.origin > lifetime)
            {
                Main.addTempTask(new Runnable()
                {
                    public void run() {
                        removeParticle(p);
                    }
                });
            }

    }
    private void drawParticle(Graphics2D g, Particle p, double scale, int x, int y)
    {
        int width = (int) (image.getWidth() * scale * p.scale);
        int height = (int) (image.getHeight() * scale * p.scale);
        g.drawImage(image, (int) (x - width/2), (int) (y - height/2), width, height, null);
    }
    public void destructor(Part oldPart) throws WorldsException
    {
        part = null;
    }
    @Override
    public void step()
    {
        if(part == null)
            return;
        if(Math.random() < rate)
        {
            float randForce = (float) ((Math.random() * 2) - 1);
            Vec2D v = force.add(randomness.mul(randForce));
            double a = v.div(v.length()).toAngle();
            a += Math.toRadians(part.getRotation());
            v = new Vec2D(a).mul(v.length());

            Vec2D p = part.getPosition();
            addParticle(new Particle(p, v));
        }

        for(final Particle p : particles)
        {
            stepParticle(p);
        }
        Main.processTempTasks();
    }
    private void addParticle(Particle p)
    {
        synchronized(particles)
        {
            particles.add(p);
        }
    }
    private void removeParticle(Particle p)
    {
        synchronized(particles)
        {
            particles.remove(p);
        }
    }
    protected class Particle {
        float[] scales = { 1f, 1f, 1f, 1f };
        float[] offsets = new float[4];
        public Particle(Vec2D pos, Vec2D velocity)
        {
            this.pos = pos;
            this.velocity = velocity;
            origin = System.currentTimeMillis();
        }

        public Particle(Vec2D pos, Vec2D velocity, Color color, int size)
        {
            this(pos, velocity);
            this.color = color;
            this.size = size;
        }
        public void setAlpha(double a)
        {
            alpha = a;
            scales[3] = (float) a;
            op = new RescaleOp(scales, offsets, null);
        }
        public Vec2D pos;
        public Vec2D velocity;
        public long origin;
        public Color color;
        public double alpha = 1;
        public double scale = 1;
        public int size;
        public RescaleOp op;
    }
}
